/**
 * @api post control.
 *
 * User: yunshengzhu
 * Date: 2020/12/23
 * Time: 下午2:05
 */
package control

import (
	"crypto/sha1"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"sort"
	"strconv"
	"time"
)

var appid string
var appsecret string

type wxconfig struct {
	appId     string
	appSecret string
	url       string
}
type json1 struct {
	Expire_time  int64
	Jsapi_ticket string
}

type json2 struct {
	Expire_time  int64
	Access_token string
}
type token struct {
	Access_token string
	Expires_in   int64
}

type ticket struct {
	Errcode    int
	Errmsg     string
	Ticket     string
	Expires_in int64
}

const jssdkKey = "go:act:jssdk"
const accessTokenKey = "go:act:access_token"

type signPackage struct {
	AppId     string `json:"appId"`
	NonceStr  string `json:"nonceStr"`
	Timestamp int64  `json:"timestamp"`
	Url       string `json:"url"`
	Signature string `json:"signature"`
	//JsApiList []string `json:"jsApiList"`
}

func New(appId string, appSecret string, url string) wxconfig {
	wx := wxconfig{appId, appSecret, url}
	return wx
}

// 创建类方法获取jssdk配置项目 返回json串
func (wx wxconfig) GetWechatConfig() *signPackage {
	appid = wx.appId
	appsecret = wx.appSecret
	//fmt.Printf("running appid: %s appsecret: %s\n", wx.appId, wx.appSecret)
	ticket := getJsApiTicket()
	timestamp := GetCurrTs()
	ts := strconv.FormatInt(timestamp, 10)
	nonceStr := getRandomString(16)
	url := wx.url
	my_string := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s", ticket, nonceStr, ts, url)
	//fmt.Println("mys_string==============", my_string)
	signature := Signature(my_string)
	signPackage := signPackage{wx.appId, nonceStr, timestamp, url, signature}
	return &signPackage
}

// 函数首字母小写 表示私有
func getJsApiTicket() string {
	json_str, _ := redisClient.Get(jssdkKey).Result()
	if json_str != "" {
		j := json1{}
		err := json.Unmarshal([]byte(json_str), &j)
		if err != nil {
			fmt.Println("111        ", err.Error())
			return ""
		}
		expire_time := j.Expire_time
		jsapi_ticket := j.Jsapi_ticket
		if expire_time < GetCurrTs() {
			// ticket过期需要从新获取
			// 获取access_token生成ticket
			access_token := getAccessToken()
			//fmt.Println("2222222         ", access_token)
			if access_token == "" {
				return ""
			}
			url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=%s", access_token)
			resp, _ := http.Get(url)
			if resp != nil {
				defer func() {
					resp.Body.Close()
				}()
			}
			body, _ := ioutil.ReadAll(resp.Body)
			//fmt.Println(string(body))
			// 解析body
			ticket := ticket{}
			err := json.Unmarshal([]byte(body), &ticket)
			if err != nil {
				fmt.Println("3333333333  ", err.Error())
				return ""
			}
			if ticket.Errcode == 0 {
				jj := json1{GetCurrTs() + 7000, ticket.Ticket}
				data, err := json.Marshal(jj)
				if err != nil {
					fmt.Println(err)
				}
				//setFile(string(data), "./jssdk/ticket.txt")
				redisClient.Set(jssdkKey, string(data), 2*time.Second)
				return ticket.Ticket
			} else {
				return ""
			}
		}

		return jsapi_ticket
	} else {
		access_token := getAccessToken()
		//fmt.Println("2222222         ", access_token)
		if access_token == "" {
			return ""
		}
		url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=%s", access_token)
		resp, _ := http.Get(url)
		if resp != nil {
			defer func() {
				resp.Body.Close()
			}()
		}
		body, _ := ioutil.ReadAll(resp.Body)
		//fmt.Println(string(body))
		// 解析body
		ticket := ticket{}
		err := json.Unmarshal([]byte(body), &ticket)
		if err != nil {
			fmt.Println("3333333333  ", err.Error())
			return ""
		}
		if ticket.Errcode == 0 {
			jj := json1{GetCurrTs() + 7000, ticket.Ticket}
			data, err := json.Marshal(jj)
			if err != nil {
				fmt.Println(err)
			}
			//setFile(string(data), "./jssdk/ticket.txt")
			redisClient.Set(jssdkKey, string(data), 2*time.Second)
			return ticket.Ticket
		} else {
			return ""
		}
	}
}

// 获取access token
func getAccessToken() string {

	// 获取ticket内容
	//json_str := readFile("./jssdk/token.txt")
	json_str, er := redisClient.Get(accessTokenKey).Result()
	fmt.Println("accesstoken     er,,,,,,,,,,,", er)
	//fmt.Println("accesstoken     json_str,,,,,,,,,,,", json_str)
	if json_str != "" {
		// 解析json串
		j := json2{}
		err := json.Unmarshal([]byte(json_str), &j)
		if err != nil {
			fmt.Println(" 333333333       ", err.Error())
			return ""
		}
		expire_time := j.Expire_time
		access_token := j.Access_token
		if expire_time < GetCurrTs() {
			// 获取新token
			url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appid, appsecret)
			resp, _ := http.Get(url)
			if resp != nil {
				defer func() {
					resp.Body.Close()
				}()
			}

			body, _ := ioutil.ReadAll(resp.Body)
			//fmt.Println(string(body))
			// 解析body
			token := token{}
			err := json.Unmarshal([]byte(body), &token)
			if err != nil {
				fmt.Println(err.Error())
				return ""
			}
			if len(token.Access_token) > 0 {
				jj := json2{GetCurrTs() + 7000, token.Access_token}
				data, err := json.Marshal(jj)
				if err != nil {
					fmt.Println(err)
				}
				//setFile(string(data), "./jssdk/token.txt")
				redisClient.Set(accessTokenKey, string(data), 2*time.Second)
				return token.Access_token
			} else {
				return ""
			}
		}
		return access_token
	} else {
		url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appid, appsecret)
		resp, _ := http.Get(url)
		//fmt.Println("req...........",resp)
		//fmt.Println("req.....err......",er)
		if resp != nil {
			defer func() {
				resp.Body.Close()
			}()
		}
		body, _ := ioutil.ReadAll(resp.Body)
		//fmt.Println(string(body))
		// 解析body
		token := token{}
		err := json.Unmarshal([]byte(body), &token)
		if err != nil {
			fmt.Println(err.Error())
			return ""
		}
		if len(token.Access_token) > 0 {
			jj := json2{GetCurrTs() + 7000, token.Access_token}
			data, err := json.Marshal(jj)
			if err != nil {
				fmt.Println(err)
			}
			//setFile(string(data), "./jssdk/token.txt")
			redisClient.Set(accessTokenKey, string(data), 2*time.Second)
			return token.Access_token
		} else {
			return ""
		}
	}

}

func timestamp() int {
	timestamp := strconv.FormatInt(time.Now().UTC().Unix(), 10)
	my_timestamp, _ := strconv.Atoi(timestamp)
	return my_timestamp
}

// 获取随机字符串
func getRandomString(l int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyz"
	bytes := []byte(str)
	result := []byte{}
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < l; i++ {
		result = append(result, bytes[r.Intn(len(bytes))])
	}
	return string(result)
}

// sha1加密
func my_sha1(data string) string {
	t := sha1.New()
	io.WriteString(t, data)
	return fmt.Sprintf("%x", t.Sum(nil))
}

//Signature sha1签名
func Signature(params ...string) string {
	sort.Strings(params)
	h := sha1.New()
	for _, s := range params {
		io.WriteString(h, s)
	}
	return fmt.Sprintf("%x", h.Sum(nil))
}

func GetCurrTs() int64 {
	return time.Now().Unix()
}
